package main

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"time"
)

type calTPS struct {
	rule       string         // log file regex rule
	re         *regexp.Regexp // log file regex
	timeLayout string         // timeLayout for datetime format
	loc        *time.Location // location for datetime format
	TPSOutput  *os.File       // fabric TPS output
}

func getFabricPeerLog() {
	c := exec.Command("bash", "-c", "./output_fabric_peer_log.sh")
	err := c.Start()
	if err != nil {
		panic(err)
	}
	err = c.Wait()
	if err != nil {
		panic(err)
	}
}

func rmFabricPeerLog() {
	c := exec.Command("rm", "./fabric_validate.log")
	err := c.Start()
	if err != nil {
		panic(err)
	}
	err = c.Wait()
	if err != nil {
		panic(err)
	}
}

func (t *calTPS) getBlockNumTimestamp(line []byte) (int, int, int64, error) {
	strfid := string(line)
	ret := t.re.FindStringSubmatch(strfid)
	blockNum, err := strconv.Atoi(ret[1])
	if err != nil {
		return 0, 0, 0, err
	}
	blockSize, err := strconv.Atoi(ret[2])
	if err != nil {
		return 0, 0, 0, err
	}
	dateTime := ret[3] + " " + ret[4]
	tmp, _ := time.ParseInLocation(t.timeLayout, dateTime, t.loc)
	timestamp := tmp.UnixNano()
	// fmt.Println(timestamp)
	return blockNum, blockSize, timestamp, nil
}

func (t *calTPS) calCurrentTps(blockNum int, blockSize int, timeDuration int64) error {
	cur_tps := int64(blockSize*1e9) / timeDuration
	content := "TPS while committing block [" + strconv.Itoa(blockNum) + "]: " + strconv.FormatInt(cur_tps, 10) + "\n"
	_, err := t.TPSOutput.Write([]byte(content))
	if err != nil {
		return err
	}
	return nil
}

func main() {
	// get fabric peer log file
	getFabricPeerLog()
	defer rmFabricPeerLog()

	fileObj, err := os.Open("./fabric_validate.log")
	if err != nil {
		panic(err)
	}
	defer fileObj.Close()

	stepLength := 20 // block count when cal tps

	calTps := calTPS{
		rule:       `.*Committed block \[([0-9]+)\] with ([0-9]+).*"time":"(.*)T(.*)Z.*`,
		timeLayout: "2006-01-02 15:04:05.999999999",
	}
	calTps.re = regexp.MustCompile(calTps.rule)
	calTps.loc, _ = time.LoadLocation("Local")
	calTps.TPSOutput, err = os.OpenFile("./farbicCurrentTPS.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		panic(err)
	}
	defer calTps.TPSOutput.Close()

	fread := bufio.NewReader(fileObj)

	line, _, err := fread.ReadLine()
	if err == io.EOF {
		return
	}
	_, _, timestamp1, err := calTps.getBlockNumTimestamp(line)
	blockSizeCount := 0
	for {
		line, _, err := fread.ReadLine()
		if err == io.EOF {
			break
		}
		blockNum, blockSize, timestamp2, err := calTps.getBlockNumTimestamp(line)
		if err != nil {
			panic(err)
		}
		blockSizeCount += blockSize
		if blockNum%stepLength == 0 {
			err = calTps.calCurrentTps(blockNum/stepLength, blockSizeCount, timestamp2-timestamp1)
			if err != nil {
				panic(err)
			}
			blockSizeCount = 0
			timestamp1 = timestamp2
		}
	}
}
